﻿using Microsoft.IdentityModel.Tokens;
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;

namespace PowerHub.MES.Jwt
{
    /// <summary>
    /// 微软 System.IdentityModel.Tokens.Jwt 
    /// </summary>
    public class JwtService
    {

        private TokenValidationParameters _tokenValidationParameters { get; set; }


        public JwtService(TokenValidationParameters tokenValidationParameters)
        {
            _tokenValidationParameters = tokenValidationParameters;
        }



        /// <summary>
        /// 颁发JWT字符串
        /// </summary>
        /// <param name="claim"></param>
        /// <param name="role"></param>
        /// <param name="expires">过期时间</param>
        /// <returns></returns>
        public string GenerateJwtToken(Claim claim, TokenModel tokenModel, DateTime expires)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[]
                {
                   claim,
                   new Claim(ClaimTypes.Role,tokenModel.Role),
                   new Claim("userId", tokenModel.Uid),
                   new Claim("userName", tokenModel.UserName)
                }),
                Expires = expires,
                SigningCredentials = new SigningCredentials(_tokenValidationParameters.IssuerSigningKey, SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);

            return tokenHandler.WriteToken(token);
        }

        /// <summary>
        /// 解析
        /// </summary>
        /// <param name="token"></param>
        /// <returns></returns>
        public static TokenModel GetUserIdFromJwtToken(string token)
        {
            var tokenHandler = new JwtSecurityTokenHandler();
            var jwtToken = tokenHandler.ReadToken(token) as JwtSecurityToken;

            if (jwtToken != null)
            {
                var userIdClaim = jwtToken.Claims.FirstOrDefault(c => c.Type == "userId");
                var userNameClaim = jwtToken.Claims.FirstOrDefault(c => c.Type == "userName");
                var roleClaim = jwtToken.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Role);
                if (userIdClaim != null)
                {
                    return new TokenModel
                    {
                        Uid = userIdClaim.Value,
                        UserName = userNameClaim.Value,
                        Role = roleClaim != null ? roleClaim.Value : null
                    };
                }
            }

            return null;
        }


        /// <summary>
        ///  验证token是否合理，以及过期时间
        /// </summary>
        /// <param name="authenticationToken"></param>
        /// <param name="user"></param>
        /// <returns></returns>
        public bool ValidatedJwtToken(string authenticationToken, out ClaimsPrincipal user)
        {
            bool result = false;
            user = null;
            try
            {
                if (string.IsNullOrEmpty(authenticationToken))
                {
                    return false;
                }

                var handler = new JwtSecurityTokenHandler();
                var claimsPrincipal = handler.ValidateToken(authenticationToken, _tokenValidationParameters,
                    out SecurityToken validatedToken);

                result = claimsPrincipal.Identity.IsAuthenticated;
                user = claimsPrincipal;
            }
            catch (SecurityTokenExpiredException stee)
            {
                // Token已过期
                throw new SecurityTokenExpiredException("Token已过期");
            }
            catch (SecurityTokenException ste)
            {
                // Token验证失败
                throw new SecurityTokenException("验证失败,你的Token似乎存在错误");
            }
            catch (Exception e)
            {
                // 其他异常
                throw new Exception("发生异常：" + e.Message);
            }
            return result;
        }


    }
}
